/**
 * 
 */
package org.mhz.sit.controller;

import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.ResourceBundle;

import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.ChoiceBox;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableColumn.CellEditEvent;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.control.Tooltip;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.image.ImageView;
import javafx.util.Callback;

import org.apache.commons.collections.CollectionUtils;
import org.mhz.sit.custom.EditingCell;
import org.mhz.sit.entity.Language;
import org.mhz.sit.entity.Settings;
import org.mhz.sit.entity.Speaker;
import org.mhz.sit.entity.SpeakerOffTopicOrder;
import org.mhz.sit.entity.SpeakerOrder;
import org.mhz.sit.service.ConfigureLanguageService;
import org.mhz.sit.service.ConfigureSettingsService;
import org.mhz.sit.service.ConfigureSpeakersService;
import org.mhz.sit.service.LanguageService;
import org.mhz.sit.service.SettingsService;
import org.mhz.sit.service.SpeakerService;
import org.mhz.sit.util.AlertUtil;
import org.mhz.sit.util.Constants;
import org.mhz.sit.util.DatabaseUtil;
import org.mhz.sit.util.SettingsUtil;
import org.mhz.sit.util.SpeakerUtil;
import org.mhz.sit.util.ValidationUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author Mahan
 *
 * Configuration and Settings controller
 */
public class ConfigAndSettingsController implements Initializable
{
    private static final Logger LOGGER = LoggerFactory.getLogger(ConfigAndSettingsController.class);

    private ObservableList<String> observableLanguageList = null;
    
    private List<String> langDescrList = new ArrayList<String>();
    
    @FXML private TableView<Speaker> speakerTbl = new TableView<Speaker>();
    @FXML private TableColumn<Speaker,String> speakerIDCol = new TableColumn<Speaker,String>();
    @FXML private TableColumn<Speaker,String> speakerNameCol = new TableColumn<Speaker,String>();
    
    @FXML private TextField speakerIDField = new TextField();
    @FXML private TextField speakerNameField = new TextField();
    
    @FXML private ChoiceBox<String> languageChoiceBox = new ChoiceBox<String>();
    
    @FXML private TextField timeLimitField = new TextField();
    @FXML private TextField topicField = new TextField();
    @FXML private ImageView successfulSaveImage = new ImageView();
    @FXML private ImageView successfulClearOffTopicImage = new ImageView();
    @FXML private ImageView successfulClearSpeakerOrderImage = new ImageView();
    @FXML private ImageView successfulClearSpeakerConfigImage = new ImageView();
    
    private SpeakerService mConfigureSpeakersService = new ConfigureSpeakersService();
    private LanguageService mConfigureLanguageService = new ConfigureLanguageService();
    private SettingsService mConfigureSettingsService = new ConfigureSettingsService();
    
    /* (non-Javadoc)
     * @see javafx.fxml.Initializable#initialize(java.net.URL, java.util.ResourceBundle)
     */
    @Override
    public void initialize(final URL aArg0, final ResourceBundle aArg1)
    {        
        // Remove the successful tick images
        successfulSaveImage.setOpacity(Constants.NO_OPACITY);
        successfulClearOffTopicImage.setOpacity(Constants.NO_OPACITY);
        successfulClearSpeakerOrderImage.setOpacity(Constants.NO_OPACITY);
        successfulClearSpeakerConfigImage.setOpacity(Constants.NO_OPACITY);
        
        //Enabling editing
        speakerTbl.setEditable(true);
        
        final Tooltip mustBeANumberToolTip = new Tooltip(Constants.MUST_BE_A_NUMBER);
        speakerIDField.setTooltip(mustBeANumberToolTip);
        timeLimitField.setTooltip(mustBeANumberToolTip);
        
        final Tooltip atLeastTwoCharsToolTip = new Tooltip(Constants.MUST_BE_AT_LEAST_2_CHARS);
        speakerNameField.setTooltip(atLeastTwoCharsToolTip);        
               
        speakerIDCol.setCellValueFactory(new PropertyValueFactory<Speaker,String>(Constants.SPEAKER_ID_PROP));        
        speakerNameCol.setCellValueFactory(new PropertyValueFactory<Speaker,String>(Constants.SPEAKER_NAME_PROP));
        
        final Callback<TableColumn<Speaker, String>, TableCell<Speaker, String>> cellFactory = 
                new Callback<TableColumn<Speaker, String>, TableCell<Speaker, String>>()
        {
            public TableCell<Speaker, String> call(final TableColumn<Speaker, String> p)
            {
                return new EditingCell();
            }
        };
            
        speakerNameCol.setCellFactory(cellFactory);
        
        // Modifying the name property
        speakerNameCol.setOnEditCommit(new EventHandler<CellEditEvent<Speaker, String>>()
        {
            @Override
            public void handle(final CellEditEvent<Speaker, String> aTable)
            {
                final Speaker speaker = aTable.getRowValue();                
                ((Speaker) aTable.getTableView().getItems().get(aTable.getTablePosition().getRow())).setName(aTable.getNewValue());
                mConfigureSpeakersService.updateSpeaker(speaker);
            }
        });
        
        // If the speaker list is empty
        if (CollectionUtils.isEmpty(SpeakerUtil.getObservableSpeakerList()))
        {            
            // Get the speakers
            final List<Speaker> speakers = mConfigureSpeakersService.getList();   
            SpeakerUtil.setObservableSpeakerList(FXCollections.observableList(speakers));
        }        
        
        speakerTbl.setItems(SpeakerUtil.getObservableSpeakerList());
                
        LOGGER.debug("Speakers table data: " + SpeakerUtil.getObservableSpeakerList());
        
        // Get the languages
        final List<Language> languages = mConfigureLanguageService.getList();
        
        if (CollectionUtils.isNotEmpty(languages))
        {
            for (Language lang : languages)
            {
                langDescrList.add(lang.getDescription());
            }
            
            observableLanguageList = FXCollections.observableList(langDescrList);
        }
        
        languageChoiceBox.setItems(observableLanguageList);           
        
        LOGGER.debug("Languages: " + observableLanguageList.toString());
        
        // If the settings are empty
        if (CollectionUtils.isEmpty(SettingsUtil.getSettingsList()))
        {        
            // Get the settings
            SettingsUtil.setSettingsList(FXCollections.observableList(mConfigureSettingsService.getList()));
        }
        
        LOGGER.debug("Settings: " + SettingsUtil.getSettingsList());         
        
        if (CollectionUtils.isNotEmpty(SettingsUtil.getSettingsList()))
        {
            for (Settings settings : SettingsUtil.getSettingsList())
            {
                if (settings.getType().equalsIgnoreCase(Constants.LANGUAGE))
                {
                    languageChoiceBox.getSelectionModel().select(settings.getValue());
                }
                else if (settings.getType().equalsIgnoreCase(Constants.TIME_LIMIT))
                {
                    timeLimitField.setText(settings.getValue());
                }
                else if (settings.getType().equalsIgnoreCase(Constants.TOPIC))
                {
                    topicField.setText(settings.getValue());
                }
            }
        }                
    }

    /**
     * Handle clicking the Add button
     *
     * @param event - The event
     */
    @FXML protected void handleAddSpeakerButtonClick(ActionEvent event)
    {               
        final String id = speakerIDField.getText();
        final String name = speakerNameField.getText();
        
        ValidationUtil.textFieldMustContainANumber(id, speakerIDField);
        ValidationUtil.checkDuplicateSpeaker(Integer.valueOf(id), SpeakerUtil.getObservableSpeakerList(), speakerIDField);
        ValidationUtil.textFieldIsAtLeastTwoCharacters(name, speakerNameField);
        
        final Speaker speakerToAdd = new Speaker(Integer.valueOf(id), name);
        
        mConfigureSpeakersService.addSpeaker(speakerToAdd, SpeakerUtil.getObservableSpeakerList());     
    }    
    
    /**
     * Handle clicking the Delete button
     *
     * @param event - The event
     */
    @FXML protected void handleDeleteSpeakerButtonClick(ActionEvent event)
    {              
        final Speaker speakerToDelete = speakerTbl.getSelectionModel().getSelectedItem();
        
        LOGGER.debug("Deleting speaker " + speakerToDelete);
                
        mConfigureSpeakersService.deleteSpeaker(speakerToDelete, SpeakerUtil.getObservableSpeakerList());                      
    }    
    
    /**
     * Handle clicking the Save settings button
     *
     * @param event - The event
     */
    @FXML protected void handleSaveSettingsButtonClick(ActionEvent event)
    {   
        SpeakerUtil.fadeOutImage(successfulSaveImage);
        
        final String timeLimit = timeLimitField.getText();
        final String topic = topicField.getText();
        
        ValidationUtil.textFieldMustContainANumber(timeLimit, timeLimitField);
        
        Settings languageSettings = new Settings();
        Settings timeSettings = new Settings();
        Settings topicSettings = new Settings();
        
        if (CollectionUtils.isNotEmpty(SettingsUtil.getSettingsList()))
        {
            for (Settings settings : SettingsUtil.getSettingsList())
            {
                if (settings.getType().equalsIgnoreCase(Constants.LANGUAGE))
                {
                    languageSettings = settings;
                }
                else if (settings.getType().equalsIgnoreCase(Constants.TIME_LIMIT))
                {
                    timeSettings = settings;
                }
                else if (settings.getType().equalsIgnoreCase(Constants.TOPIC))
                {
                    topicSettings = settings;
                }                
            }
        }
                
        languageSettings.setValue(languageChoiceBox.getSelectionModel().getSelectedItem());    
        
        // If the Id is null then this is a new setting so add it to the list
        if (languageSettings.getId() == null)
        {
            languageSettings.setType(Constants.LANGUAGE);
            SettingsUtil.getSettingsList().add(languageSettings);
        }
        
        timeSettings.setValue(timeLimit);
        
        // If the Id is null then this is a new setting so add it to the list
        if (timeSettings.getId() == null)
        {      
            timeSettings.setType(Constants.TIME_LIMIT);
            SettingsUtil.getSettingsList().add(timeSettings);     
        }
        
        topicSettings.setValue(topic);
        
        // If the Id is null then this is a new setting so add it to the list
        if (topicSettings.getId() == null)
        {      
            topicSettings.setType(Constants.TOPIC);
            SettingsUtil.getSettingsList().add(topicSettings);     
        }
        
        LOGGER.debug("Saving settings " + SettingsUtil.getSettingsList());
                
        mConfigureSettingsService.saveSettings(SettingsUtil.getSettingsList());      
        
        SpeakerUtil.fadeInImage(successfulSaveImage);
    }         

    /**
     * Handle clear off topic button click
     *
     * @param event - The event
     */
    @FXML protected void handleClearOffTopicButtonClick(ActionEvent event)
    {  
        SpeakerUtil.fadeOutImage(successfulClearOffTopicImage);
        
        if (CollectionUtils.isNotEmpty(SpeakerUtil.getObservableOffTopicOrderList()))
        {
            final int deleteCount = DatabaseUtil.deleteAllData(SpeakerOffTopicOrder.class.getName());
        
            final int listSize = SpeakerUtil.getObservableOffTopicOrderList().size();

            LOGGER.debug("Off topic deleteCount " + deleteCount + ", listSize " + listSize);
            
            // If the deleted are the same as the list size then clear the list
            if (deleteCount >= listSize)
            {
                SpeakerUtil.getObservableOffTopicOrderList().clear();
            }
            else
            {
                AlertUtil.displayAlert(Constants.SIT_999_ACTION_NOT_FULLY_COMPLETED);
            }            
        }
        
        SpeakerUtil.fadeInImage(successfulClearOffTopicImage);
    }
    
    /**
     * Handle clear speaker order button
     *
     * @param event - The event
     */
    @FXML protected void handleClearSpeakerOrderButtonClick(ActionEvent event)
    {  
        SpeakerUtil.fadeOutImage(successfulClearSpeakerOrderImage);

        // If the speaker order list or the current speaker have a value(s)
        if (CollectionUtils.isNotEmpty(SpeakerUtil.getObservableOrderOfSpeakersList())
            || (SpeakerUtil.getCurrentSpeaker() != null))
        {
            final int deleteCount = DatabaseUtil.deleteAllData(SpeakerOrder.class.getName());
        
            int speakerOrderListSize = 0;
            
            if (SpeakerUtil.getCurrentSpeaker() != null)
            {
                speakerOrderListSize++;
            }
            
            if (CollectionUtils.isNotEmpty(SpeakerUtil.getObservableOrderOfSpeakersList()))
            {
                speakerOrderListSize += SpeakerUtil.getObservableOrderOfSpeakersList().size();
            }

            LOGGER.debug("Speaker order deleteCount " + deleteCount + ", speakerOrderListSize " + speakerOrderListSize);
            
            // If the deleted are the same as the list size then clear the list
            if (deleteCount >= speakerOrderListSize)
            {
                SpeakerUtil.getObservableOrderOfSpeakersList().clear();
                SpeakerUtil.setCurrentSpeaker(null);
            }
            else
            {
                AlertUtil.displayAlert(Constants.SIT_999_ACTION_NOT_FULLY_COMPLETED);
            }
        }
        
        SpeakerUtil.fadeInImage(successfulClearSpeakerOrderImage);        
    }
    
    /**
     * Handle speaker config button
     *
     * @param event - The event
     */
    @FXML protected void handleClearSpeakerConfigButtonClick(ActionEvent event)
    {  
        SpeakerUtil.fadeOutImage(successfulClearSpeakerConfigImage);
        
        if (CollectionUtils.isNotEmpty(SpeakerUtil.getObservableSpeakerList()))
        {
            final int deleteCount = DatabaseUtil.deleteAllData(Speaker.class.getName());
        
            final int listSize = SpeakerUtil.getObservableSpeakerList().size();

            LOGGER.debug("Speaker config deleteCount " + deleteCount + ", listSize " + listSize);
            
            // If the deleted are the same as the list size then clear the list
            if (deleteCount >= listSize)
            {
                SpeakerUtil.getObservableSpeakerList().clear();
            }
            else
            {
                AlertUtil.displayAlert(Constants.SIT_999_ACTION_NOT_FULLY_COMPLETED);
            }            
        }
        
        SpeakerUtil.fadeInImage(successfulClearSpeakerConfigImage);         
    }    
}
